package juc.ProducerCnosumer;

import java.util.EnumMap;
import java.util.Map;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
 * @author 马迪迪
 * @description: TODO
 * @data 2025年09月15日22时32分
 */

public class Store {
    // 库存上限
    private static final int MAX_STOCK = 50;
    // 最大同时消费人数
    private static final int MAX_CONSUMER = 8;

    // 库存：商品->数量
    private final Map<Goods, Integer> stock = new EnumMap<>(Goods.class);
    // 厂家定价：商品->单价（不同商品独立定价）
    private final Map<Goods, Double> factoryPrice = new EnumMap<>(Goods.class);

    // 生产者统计：商品->生产总量、商品->生产总金额
    private final Map<Goods, Integer> produceTotal = new EnumMap<>(Goods.class);
    private final Map<Goods, Double> produceAmount = new EnumMap<>(Goods.class);

    // 消费者统计：商品->消费总量、商品->消费总金额、成功/失败人数
    private final Map<Goods, Integer> consumeTotal = new EnumMap<>(Goods.class);
    private final Map<Goods, Double> consumeAmount = new EnumMap<>(Goods.class);
    private int successConsumerCount = 0;
    private int failConsumerCount = 0;

    // 线程安全控制
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition stockCondition = lock.newCondition(); // 库存等待通知
    private final Semaphore consumerSemaphore = new Semaphore(MAX_CONSUMER); // 消费人数限制
    private volatile boolean isRunning = true; // 运行状态（控制线程停止）

    // 初始化：库存0，设置各商品厂家定价
    public Store() {
        for (Goods goods : Goods.values()) {
            stock.put(goods, 0);
            factoryPrice.put(goods, getRandomFactoryPrice()); // 随机厂家定价（1-10元）
            produceTotal.put(goods, 0);
            produceAmount.put(goods, 0.0);
            consumeTotal.put(goods, 0);
            consumeAmount.put(goods, 0.0);
        }
    }

    // 生成随机厂家定价（1-10元，保留1位小数）
    private double getRandomFactoryPrice() {
        return Math.round((1 + Math.random() * 9) * 10) / 10.0;
    }

    // 生产者生产商品（补满库存）
    public void produce(Goods goods) {
        lock.lock();
        try {
            if (!isRunning) return;

            // 计算需生产数量（补到MAX_STOCK）
            int current = stock.get(goods);
            int needProduce = MAX_STOCK - current;
            if (needProduce <= 0) return;

            // 更新库存
            stock.put(goods, current + needProduce);
            // 更新生产者统计
            int total = produceTotal.get(goods) + needProduce;
            produceTotal.put(goods, total);
            double amount = produceAmount.get(goods) + needProduce * factoryPrice.get(goods);
            produceAmount.put(goods, amount);

            System.out.printf("[生产者] 生产%s：数量%d，单价%.1f元，当前库存%d%n",
                    goods, needProduce, factoryPrice.get(goods), stock.get(goods));

            // 通知等待的消费者
            stockCondition.signalAll();
        } finally {
            lock.unlock();
        }
    }

    // 消费者购买商品
    public void consume() {
        // 控制同时消费人数（获取许可）
        try {
            consumerSemaphore.acquire();
            if (!isRunning) return;

            lock.lock();
            try {
                // 随机选择商品类型和数量（1-10）
                Goods goods = Goods.values()[(int) (Math.random() * Goods.values().length)];
                int buyCount = (int) (Math.random() * 10) + 1;
                int retryCount = 0; // 重试1次（符合"重置选择"需求）

                while (retryCount < 2) {
                    int currentStock = stock.get(goods);
                    if (currentStock >= buyCount) {
                        // 库存足够：扣减库存，更新统计
                        stock.put(goods, currentStock - buyCount);
                        int totalConsume = consumeTotal.get(goods) + buyCount;
                        consumeTotal.put(goods, totalConsume);
                        double consumeAmt = consumeAmount.get(goods) + buyCount * factoryPrice.get(goods);
                        consumeAmount.put(goods, consumeAmt);
                        successConsumerCount++;

                        System.out.printf("[消费者] 购买成功：%s%d个，单价%.1f元，剩余库存%d%n",
                                goods, buyCount, factoryPrice.get(goods), stock.get(goods));
                        return;
                    } else {
                        // 库存不足：重试1次（重新选商品和数量）
                        retryCount++;
                        if (retryCount == 1) {
                            System.out.printf("[消费者] 购买失败：%s库存不足（需%d，有%d），重试1次%n",
                                    goods, buyCount, currentStock);
                            goods = Goods.values()[(int) (Math.random() * Goods.values().length)];
                            buyCount = (int) (Math.random() * 10) + 1;
                        }
                    }
                }

                // 重试后仍失败，触发紧急生产
                System.out.printf("[消费者] 购买失败：两次选择均无足够库存，触发紧急生产%n");
                triggerEmergencyProduction(goods);
                failConsumerCount++;
            } finally {
                lock.unlock();
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            // 释放消费许可
            consumerSemaphore.release();
        }
    }

    // 停止所有线程
    public void stop() {
        isRunning = false;
        lock.lock();
        try {
            stockCondition.signalAll(); // 唤醒所有等待的线程
        } finally {
            lock.unlock();
        }
    }

    // 打印当日统计
    public void printDailyStat() {
        lock.lock();
        try {
            System.out.println("\n==================== 当日统计 ====================");
            // 生产者统计
            System.out.println("1. 生产者统计：");
            for (Goods goods : Goods.values()) {
                System.out.printf("   %s：生产总量%d，单价%.1f元，总金额%.1f元%n",
                        goods, produceTotal.get(goods), factoryPrice.get(goods), produceAmount.get(goods));
            }

            // 店家（消费者）统计
            System.out.println("\n2. 店家统计：");
            System.out.printf("   成功消费人数：%d，失败消费人数：%d%n", successConsumerCount, failConsumerCount);
            for (Goods goods : Goods.values()) {
                System.out.printf("   %s：消费总量%d，消费总金额%.1f元%n",
                        goods, consumeTotal.get(goods), consumeAmount.get(goods));
            }
            System.out.println("==================================================");
        } finally {
            lock.unlock();
        }
    }

    // 紧急生产指定商品
    private void triggerEmergencyProduction(Goods goods) {
        // 计算需生产数量（补到足够满足最大需求）
        int current = stock.get(goods);
        int needProduce = 10 - current; // 最大需求为10

        if (needProduce <= 0) return;

        // 更新库存
        stock.put(goods, current + needProduce);
        // 更新生产者统计
        int total = produceTotal.get(goods) + needProduce;
        produceTotal.put(goods, total);
        double amount = produceAmount.get(goods) + needProduce * factoryPrice.get(goods);
        produceAmount.put(goods, amount);

        System.out.printf("[紧急生产] 生产%s：数量%d，单价%.1f元，当前库存%d%n",
                goods, needProduce, factoryPrice.get(goods), stock.get(goods));

        // 通知等待的消费者
        stockCondition.signalAll();
    }

    public boolean isRunning() {
        return isRunning;
    }
}